// Node.js + Express 后端示例代码
// 仅供参考，需要根据实际情况调整

const express = require('express');
const mysql = require('mysql2/promise');
const axios = require('axios');
const multer = require('multer');
const path = require('path');
const fs = require('fs');

const app = express();
app.use(express.json());

// CORS 跨域配置
app.use((req, res, next) => {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
    res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
    if (req.method === 'OPTIONS') {
        return res.sendStatus(200);
    }
    next();
});


// 数据库连接池 - 远程MySQL
const pool = mysql.createPool({
    host: 'YOUR_DATABASE_HOST',        // 数据库地址
    port: 3306,                         // MySQL端口（默认3306）
    user: 'YOUR_DATABASE_USER',         // 数据库用户名
    password: 'YOUR_DATABASE_PASSWORD', // 数据库密码
    database: 'YOUR_DATABASE_NAME',     // 数据库名
    waitForConnections: true,
    connectionLimit: 10,
    queueLimit: 0,
    connectTimeout: 10000               // 连接超时时间（10秒）
});

// 初始化微信通知模块的数据库连接
const wechatNotify = require('./wechat-notify.js');
wechatNotify.setDatabasePool(pool);

// 微信小程序配置
const wxConfig = {
    appId: 'YOUR_WECHAT_APP_ID',
    appSecret: 'YOUR_WECHAT_APP_SECRET'
};

// ==========================================
// 工具函数
// ==========================================

// 获取微信 Access Token
async function getWxAccessToken() {
    const url = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${wxConfig.appId}&secret=${wxConfig.appSecret}`;
    const response = await axios.get(url);
    return response.data.access_token;
}

// 发送订阅消息
async function sendSubscribeMessage(openid, templateId, data) {
    try {
        const accessToken = await getWxAccessToken();
        const url = `https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=${accessToken}`;

        await axios.post(url, {
            touser: openid,
            template_id: templateId,
            data: data
        });
    } catch (error) {
        console.error('发送订阅消息失败:', error);
    }
}

// ==========================================
// 健康检查接口
// ==========================================

// 根路径 - 服务状态检查
app.get('/', (req, res) => {
    res.json({
        code: 0,
        success: true,
        message: '设备报修系统API服务运行正常',
        version: '1.0.0',
        timestamp: new Date().toISOString()
    });
});

// 微信业务域名验证 - 静态文件服务
// 访问地址: /pages/index/WXPThXXBHD.txt
app.use('/pages', express.static(path.join(__dirname, 'pages')));

// 健康检查接口
app.get('/health', async (req, res) => {
    try {
        // 测试数据库连接
        await pool.execute('SELECT 1');

        res.json({
            code: 0,
            success: true,
            message: 'API服务和数据库连接正常',
            database: 'connected',
            timestamp: new Date().toISOString()
        });
    } catch (error) {
        res.status(500).json({
            code: 9999,
            success: false,
            message: '数据库连接失败',
            database: 'disconnected',
            error: error.message
        });
    }
});

// ==========================================
// 用户接口
// ==========================================

// 用户登录
app.post('/api/user/login', async (req, res) => {
    try {
        const { code } = req.body;

        if (!code) {
            return res.json({ code: 1001, success: false, message: '缺少登录凭证code' });
        }

        // 调用微信接口获取 openid
        const url = `https://api.weixin.qq.com/sns/jscode2session?appid=${wxConfig.appId}&secret=${wxConfig.appSecret}&js_code=${code}&grant_type=authorization_code`;
        const response = await axios.get(url);

        console.log('微信登录响应:', response.data);

        // 检查微信接口返回
        if (response.data.errcode) {
            console.error('微信登录错误:', response.data);
            return res.json({
                code: 9999,
                success: false,
                message: `微信登录失败: ${response.data.errmsg}`
            });
        }

        const { openid, session_key } = response.data;

        if (!openid) {
            console.error('未获取到openid:', response.data);
            return res.json({ code: 9999, success: false, message: '获取openid失败' });
        }

        // 查询用户信息
        const [rows] = await pool.execute(
            'SELECT * FROM users WHERE openid = ?',
            [openid]
        );

        let isAdmin = false;
        let isRegistered = false;
        let nickname = '';
        let avatar = '';
        let role = 'user';

        if (rows.length > 0) {
            isAdmin = rows[0].is_admin === 1;
            isRegistered = rows[0].nickname ? true : false;
            nickname = rows[0].nickname;
            avatar = rows[0].avatar;
            role = rows[0].role || 'user';
        }

        // 生成 token（这里简化处理，实际应使用 JWT）
        const token = Buffer.from(`${openid}:${Date.now()}`).toString('base64');

        res.json({
            code: 0,
            success: true,
            data: {
                openid,
                sessionKey: session_key,
                token,
                isAdmin,
                isRegistered,
                nickname,
                avatar,
                role,
                phone: rows[0]?.phone || ''
            }
        });
    } catch (error) {
        console.error('登录失败:', error);
        res.json({
            code: 9999,
            success: false,
            message: '登录失败: ' + error.message
        });
    }
});

// 保存用户信息
app.post('/api/user/save', async (req, res) => {
    try {
        const { openid, nickname, avatar } = req.body;

        await pool.execute(
            'INSERT INTO users (openid, nickname, avatar) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE nickname = ?, avatar = ?',
            [openid, nickname, avatar, nickname, avatar]
        );

        res.json({ code: 0, success: true, data: {} });
    } catch (error) {
        console.error('保存用户信息失败:', error);
        res.json({ code: 9999, success: false, message: '保存失败' });
    }
});

// 设置用户角色
app.post('/api/user/set-role', async (req, res) => {
    try {
        const { openid, role, teacherId } = req.body;

        // validate role
        if (!['student', 'teacher'].includes(role)) {
            return res.json({ code: 2001, success: false, message: '无效的角色' });
        }

        // 学生角色需要teacher_id
        if (role === 'student' && !teacherId) {
            return res.json({ code: 2002, success: false, message: '学生角色需要指定指导教师' });
        }

        await pool.execute(
            'UPDATE users SET role = ?, teacher_id = ? WHERE openid = ?',
            [role, teacherId || null, openid]
        );

        res.json({ code: 0, success: true, message: '角色设置成功' });
    } catch (error) {
        console.error('设置角色失败:', error);
        res.json({ code: 9999, success: false, message: '设置失败' });
    }
});

// 获取手机号（微信接口）
app.post('/api/user/phone', async (req, res) => {
    try {
        const { code } = req.body;

        if (!code) {
            return res.json({ code: 2001, success: false, message: '缺少code参数' });
        }

        // 获取 access_token
        const tokenUrl = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${wxConfig.appId}&secret=${wxConfig.appSecret}`;
        const tokenResponse = await axios.get(tokenUrl);

        if (!tokenResponse.data.access_token) {
            console.error('获取access_token失败:', tokenResponse.data);
            return res.json({ code: 9999, success: false, message: '获取access_token失败' });
        }

        const accessToken = tokenResponse.data.access_token;

        // 获取手机号
        const phoneUrl = `https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=${accessToken}`;
        const phoneResponse = await axios.post(phoneUrl, { code });

        if (phoneResponse.data.errcode === 0) {
            const phoneInfo = phoneResponse.data.phone_info;
            res.json({
                code: 0,
                success: true,
                data: {
                    phone: phoneInfo.purePhoneNumber || phoneInfo.phoneNumber
                }
            });
        } else {
            console.error('获取手机号失败:', phoneResponse.data);
            res.json({
                code: phoneResponse.data.errcode,
                success: false,
                message: phoneResponse.data.errmsg || '获取手机号失败'
            });
        }
    } catch (error) {
        console.error('获取手机号异常:', error);
        res.json({ code: 9999, success: false, message: '服务器错误' });
    }
});

// 用户注册
app.post('/api/user/register', async (req, res) => {
    try {
        const { openid, nickname, avatar, phone } = req.body;

        // 获取客户端IP
        const clientIp = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
        const ip = clientIp.split(',')[0].trim(); // 处理多IP情况

        // 频率限制检查 (每小时3次，超过封禁24小时)
        const [limits] = await pool.execute(
            'SELECT * FROM registration_limits WHERE identifier = ?',
            [ip]
        );

        if (limits.length > 0) {
            const limit = limits[0];
            const now = new Date();

            // 检查是否被封禁
            if (limit.blocked_until && new Date(limit.blocked_until) > now) {
                return res.json({
                    code: 1005,
                    success: false,
                    message: '注册过于频繁，请24小时后再试'
                });
            }

            // 检查每小时频率
            const oneHourAgo = new Date(now - 60 * 60 * 1000);
            if (new Date(limit.first_attempt) > oneHourAgo) {
                if (limit.attempt_count >= 3) {
                    // 触发封禁
                    const blockedUntil = new Date(now.getTime() + 24 * 60 * 60 * 1000);
                    await pool.execute(
                        'UPDATE registration_limits SET blocked_until = ? WHERE id = ?',
                        [blockedUntil, limit.id]
                    );
                    return res.json({
                        code: 1005,
                        success: false,
                        message: '注册过于频繁，请24小时后再试'
                    });
                } else {
                    // 增加计数
                    await pool.execute(
                        'UPDATE registration_limits SET attempt_count = attempt_count + 1, last_attempt = NOW() WHERE id = ?',
                        [limit.id]
                    );
                }
            } else {
                // 超过一小时，重置计数
                await pool.execute(
                    'UPDATE registration_limits SET attempt_count = 1, first_attempt = NOW(), last_attempt = NOW() WHERE id = ?',
                    [limit.id]
                );
            }
        } else {
            // 新IP记录
            await pool.execute(
                'INSERT INTO registration_limits (identifier, attempt_count) VALUES (?, 1)',
                [ip]
            );
        }

        if (!openid || !nickname) {
            return res.json({ code: 1001, success: false, message: '缺少必要参数' });
        }

        // 1. 验证 OpenID 格式 (防止SQL注入)
        // 微信 OpenID 通常是 28 位字符，包含字母、数字、下划线、减号
        const openidRegex = /^[a-zA-Z0-9_-]{10,64}$/;
        if (!openidRegex.test(openid)) {
            return res.json({
                code: 1002,
                success: false,
                message: '无效的用户标识'
            });
        }

        // 2. 验证昵称 (防止XSS和SQL注入)
        // 移除危险字符，只允许中文、字母、数字、常见符号
        if (nickname) {
            // 检查是否包含 SQL 注入关键字
            const sqlKeywords = /\b(union|select|insert|update|delete|drop|truncate|alter|create|grant|revoke)\b/i;
            if (sqlKeywords.test(nickname)) {
                return res.json({
                    code: 1003,
                    success: false,
                    message: '昵称包含非法字符'
                });
            }

            // 限制长度
            if (nickname.length > 50) {
                return res.json({
                    code: 1003,
                    success: false,
                    message: '昵称过长'
                });
            }
        }

        // 3. 验证手机号
        if (phone) {
            const phoneRegex = /^1[3-9]\d{9}$/;
            if (!phoneRegex.test(phone)) {
                return res.json({
                    code: 1004,
                    success: false,
                    message: '无效的手机号码'
                });
            }
        }

        // 更新或插入用户信息
        await pool.execute(
            `INSERT INTO users (openid, nickname, avatar, phone, created_at) 
             VALUES (?, ?, ?, ?, NOW()) 
             ON DUPLICATE KEY UPDATE nickname = ?, avatar = ?, phone = ?, updated_at = NOW()`,
            [openid, nickname, avatar, phone || null, nickname, avatar, phone || null]
        );

        // 同步更新该用户的历史报修单信息
        await pool.execute(
            'UPDATE repair_orders SET user_name = ?, user_avatar = ? WHERE openid = ?',
            [nickname, avatar, openid]
        );

        res.json({ code: 0, success: true, message: '注册成功', data: {} });
    } catch (error) {
        console.error('注册失败:', error);
        res.json({ code: 9999, success: false, message: '注册失败: ' + error.message });
    }
});

// ==========================================
// 管理员设置接口（临时使用，设置完可删除）
// ==========================================});

// 更新用户角色（设置或取消管理员）
app.post('/api/admin/update-role', async (req, res) => {
    try {
        const { openid, isAdmin, role, adminKey } = req.body;

        // 安全密钥验证
        const ADMIN_SECRET_KEY = 'YOUR_ADMIN_SECRET_KEY';

        if (adminKey !== ADMIN_SECRET_KEY) {
            return res.json({ code: 1003, success: false, message: '密钥错误，无权限操作' });
        }

        if (!openid) {
            return res.json({ code: 1001, success: false, message: '缺少openid参数' });
        }

        // 构建更新语句
        let sql = 'UPDATE users SET ';
        const params = [];
        const updates = [];

        if (isAdmin !== undefined) {
            updates.push('is_admin = ?');
            params.push(isAdmin ? 1 : 0);
        }

        if (role !== undefined) {
            updates.push('role = ?');
            params.push(role);

            // 自动同步 is_admin 标志
            if (role === 'admin') {
                if (!updates.includes('is_admin = ?')) {
                    updates.push('is_admin = ?');
                    params.push(1);
                } else {
                    // 如果已经包含了 is_admin 更新，确保它是1
                    const adminIndex = updates.indexOf('is_admin = ?');
                    params[adminIndex] = 1;
                }
            } else if (isAdmin === undefined) {
                // 如果设置为非 admin 角色，且没有明确指定 isAdmin，则设置为0
                updates.push('is_admin = ?');
                params.push(0);
            }
        }

        if (updates.length === 0) {
            return res.json({ code: 0, success: true, message: '无变更' });
        }

        sql += updates.join(', ') + ' WHERE openid = ?';
        params.push(openid);

        // 更新用户角色
        const [result] = await pool.execute(sql, params);

        if (result.affectedRows === 0) {
            return res.json({
                code: 2001,
                success: false,
                message: '用户不存在'
            });
        }

        res.json({
            code: 0,
            success: true,
            message: '用户权限/角色已更新',
            data: { openid, isAdmin, role }
        });
    } catch (error) {
        console.error('更新角色失败:', error);
        res.json({ code: 9999, success: false, message: '更新失败: ' + error.message });
    }
});

// 更新用户信息（姓名、手机号）
app.post('/api/admin/update-user-info', async (req, res) => {
    const connection = await pool.getConnection();
    try {
        await connection.beginTransaction();

        const { openid, nickname, phone, adminKey } = req.body;

        // 安全密钥验证
        const ADMIN_SECRET_KEY = 'YOUR_ADMIN_SECRET_KEY';
        if (adminKey !== ADMIN_SECRET_KEY) {
            return res.json({ code: 1003, success: false, message: '密钥错误，无权限操作' });
        }

        if (!openid) {
            return res.json({ code: 1001, success: false, message: '缺少openid参数' });
        }

        // 1. 更新用户表
        const [result] = await connection.execute(
            'UPDATE users SET nickname = ?, phone = ? WHERE openid = ?',
            [nickname, phone, openid]
        );

        if (result.affectedRows === 0) {
            await connection.rollback();
            return res.json({ code: 2001, success: false, message: '用户不存在' });
        }

        // 2. 同步更新历史工单中的姓名
        if (nickname) {
            await connection.execute(
                'UPDATE repair_orders SET user_name = ? WHERE openid = ?',
                [nickname, openid]
            );
        }

        await connection.commit();

        res.json({
            code: 0,
            success: true,
            message: '用户信息已更新',
            data: { openid, nickname, phone }
        });

    } catch (error) {
        await connection.rollback();
        console.error('更新用户信息失败:', error);
        res.json({ code: 9999, success: false, message: '更新失败: ' + error.message });
    } finally {
        connection.release();
    }
});

// 保留原setAdmin接口以保持兼容
app.post('/api/admin/set', async (req, res) => {
    // 转发到update-role，设置isAdmin=true
    req.body.isAdmin = true;
    return app._router.handle(Object.assign({}, req, {
        url: '/api/admin/update-role',
        method: 'POST'
    }), res);
});

// 获取所有用户列表（需要管理员密钥）
app.get('/api/admin/users', async (req, res) => {
    try {
        const { adminKey } = req.query;

        // 安全密钥验证
        const ADMIN_SECRET_KEY = 'YOUR_ADMIN_SECRET_KEY';

        if (adminKey !== ADMIN_SECRET_KEY) {
            return res.json({ code: 1003, success: false, message: '密钥错误，无权限操作' });
        }

        const [rows] = await pool.execute(
            'SELECT openid, nickname, is_admin, role, teacher_id, created_at FROM users ORDER BY created_at DESC'
        );

        res.json({
            code: 0,
            success: true,
            data: { list: rows }
        });
    } catch (error) {
        console.error('获取用户列表失败:', error);
        res.json({ code: 9999, success: false, message: '查询失败: ' + error.message });
    }
});

// ==========================================
// 学生管理和工单指派接口
// ==========================================

// 设置用户角色
app.post('/api/admin/set-role', async (req, res) => {
    try {
        const { openid, role, teacherId, adminKey } = req.body;

        const ADMIN_SECRET_KEY = 'YOUR_ADMIN_SECRET_KEY';
        if (adminKey !== ADMIN_SECRET_KEY) {
            return res.json({ code: 1003, success: false, message: '密钥错误，无权限操作' });
        }

        if (!openid || !role) {
            return res.json({ code: 1001, success: false, message: '缺少必要参数' });
        }

        // 验证角色值
        if (!['user', 'student', 'teacher'].includes(role)) {
            return res.json({ code: 1002, success: false, message: '无效的角色类型' });
        }

        // 如果设置为老师，同时设置is_admin=1
        const isAdmin = role === 'teacher' ? 1 : 0;

        const [result] = await pool.execute(
            'UPDATE users SET role = ?, is_admin = ?, teacher_id = ? WHERE openid = ?',
            [role, isAdmin, teacherId || null, openid]
        );

        if (result.affectedRows === 0) {
            return res.json({ code: 2001, success: false, message: '用户不存在' });
        }

        const roleNames = { user: '普通用户', student: '学生', teacher: '老师' };
        res.json({
            code: 0,
            success: true,
            message: `已设置为${roleNames[role]}`,
            data: { openid, role }
        });
    } catch (error) {
        console.error('设置角色失败:', error);
        res.json({ code: 9999, success: false, message: '设置失败: ' + error.message });
    }
});

// 获取学生列表（老师查看自己的学生，或获取所有学生）
app.get('/api/students', async (req, res) => {
    try {
        const { teacherId } = req.query;

        let sql = 'SELECT openid, nickname, avatar, phone, teacher_id, created_at FROM users WHERE role = ?';
        let params = ['student'];

        // if (teacherId) {
        //     sql += ' AND teacher_id = ?';
        //     params.push(teacherId);
        // }

        sql += ' ORDER BY created_at DESC';

        const [rows] = await pool.execute(sql, params);

        res.json({ code: 0, success: true, data: { list: rows } });
    } catch (error) {
        console.error('获取学生列表失败:', error);
        res.json({ code: 9999, success: false, message: '查询失败: ' + error.message });
    }
});

// 指派工单给学生
app.post('/api/admin/assign-order', async (req, res) => {
    const connection = await pool.getConnection();

    try {
        await connection.beginTransaction();

        const { orderId, studentOpenid, teacherOpenid } = req.body;

        if (!orderId || !studentOpenid || !teacherOpenid) {
            return res.json({ code: 1001, success: false, message: '缺少必要参数' });
        }

        // 验证学生身份
        const [studentRows] = await connection.execute(
            'SELECT nickname, role FROM users WHERE openid = ?',
            [studentOpenid]
        );

        if (studentRows.length === 0 || studentRows[0].role !== 'student') {
            await connection.rollback();
            return res.json({ code: 2001, success: false, message: '该用户不是学生' });
        }

        // 更新工单
        const [result] = await connection.execute(
            'UPDATE repair_orders SET assigned_to = ?, assigned_by = ?, assigned_at = NOW() WHERE id = ?',
            [studentOpenid, teacherOpenid, orderId]
        );

        if (result.affectedRows === 0) {
            await connection.rollback();
            return res.json({ code: 2002, success: false, message: '工单不存在' });
        }

        // 记录操作日志
        const [teacherRows] = await connection.execute(
            'SELECT nickname FROM users WHERE openid = ?',
            [teacherOpenid]
        );
        const teacherName = teacherRows.length > 0 ? teacherRows[0].nickname : '老师';

        await connection.execute(
            'INSERT INTO repair_logs (order_id, admin_openid, admin_name, action, remark) VALUES (?, ?, ?, ?, ?)',
            [orderId, teacherOpenid, teacherName, '指派工单', `指派给学生: ${studentRows[0].nickname}`]
        );

        await connection.commit();

        // TODO: 发送订阅消息给学生
        // await sendSubscribeMessage(studentOpenid, 'template_id_for_assignment', {...});

        res.json({
            code: 0,
            success: true,
            message: '指派成功',
            data: { orderId, studentName: studentRows[0].nickname }
        });

    } catch (error) {
        await connection.rollback();
        console.error('指派工单失败:', error);
        res.json({ code: 9999, success: false, message: '指派失败: ' + error.message });
    } finally {
        connection.release();
    }
});

// 获取学生的工单列表
app.get('/api/student/orders', async (req, res) => {
    try {
        const { studentOpenid, status, page = 1, pageSize = 10 } = req.query;

        if (!studentOpenid) {
            return res.json({ code: 1001, success: false, message: '缺少学生openid' });
        }

        let sql = `SELECT r.*, 
                   r.lab_name as labName, r.lab_location as labLocation,
                   r.device_type_name as deviceTypeName, r.fault_type_name as faultTypeName,
                   COALESCE(u.nickname, r.user_name, '未命名用户') as userName, u.avatar as userAvatar 
                   FROM repair_orders r 
                   LEFT JOIN users u ON r.openid COLLATE utf8mb4_unicode_ci = u.openid COLLATE utf8mb4_unicode_ci 
                   WHERE r.assigned_to = ?`;
        const params = [studentOpenid];

        if (status) {
            sql += ' AND r.status = ?';
            params.push(status);
        }

        sql += ' ORDER BY r.assigned_at DESC LIMIT ? OFFSET ?';
        params.push(parseInt(pageSize), (parseInt(page) - 1) * parseInt(pageSize));

        const [rows] = await pool.execute(sql, params);

        // 解析图片JSON
        rows.forEach(row => {
            if (row.images) {
                row.images = JSON.parse(row.images);
            }
        });

        res.json({ code: 0, success: true, data: { list: rows } });
    } catch (error) {
        console.error('查询学生工单失败:', error);
        res.json({ code: 9999, success: false, message: '查询失败: ' + error.message });
    }
});

// 获取学生工单统计
app.get('/api/student/stats', async (req, res) => {
    try {
        const { studentOpenid } = req.query;

        if (!studentOpenid) {
            return res.json({ code: 1001, success: false, message: '缺少学生openid' });
        }

        const [rows] = await pool.execute(`
            SELECT 
                COUNT(CASE WHEN status = 'pending' THEN 1 END) as pending,
                COUNT(CASE WHEN status = 'processing' THEN 1 END) as processing,
                COUNT(CASE WHEN status = 'completed' THEN 1 END) as completed,
                COUNT(*) as total
            FROM repair_orders
            WHERE assigned_to = ?
        `, [studentOpenid]);

        res.json({ code: 0, success: true, data: rows[0] });
    } catch (error) {
        console.error('查询学生统计失败:', error);
        res.json({ code: 9999, success: false, message: '查询失败: ' + error.message });
    }
});

// ==========================================
// 机房接口
// ==========================================

// 获取机房列表
app.get('/api/lab/list', async (req, res) => {
    try {
        const [rows] = await pool.execute(
            'SELECT * FROM labs WHERE status = ? ORDER BY id',
            ['active']
        );

        res.json({ code: 0, success: true, data: { list: rows } });
    } catch (error) {
        console.error('查询机房列表失败:', error);
        res.json({ code: 9999, success: false, message: '查询失败' });
    }
});

// 获取机房信息
app.get('/api/lab/info', async (req, res) => {
    try {
        const { labId } = req.query;

        const [rows] = await pool.execute(
            'SELECT * FROM labs WHERE id = ?',
            [labId]
        );

        if (rows.length === 0) {
            return res.json({ code: 2001, success: false, message: '机房不存在' });
        }

        res.json({ code: 0, success: true, data: rows[0] });
    } catch (error) {
        console.error('查询机房信息失败:', error);
        res.json({ code: 9999, success: false, message: '查询失败' });
    }
});

// 添加机房（需要管理员密钥）
app.post('/api/admin/lab/add', async (req, res) => {
    try {
        const { labId, name, location, deviceCount, remark, adminKey } = req.body;

        const ADMIN_SECRET_KEY = 'YOUR_ADMIN_SECRET_KEY';
        if (adminKey !== ADMIN_SECRET_KEY) {
            return res.json({ code: 1003, success: false, message: '密钥错误，无权限操作' });
        }

        if (!labId || !name || !location) {
            return res.json({ code: 1001, success: false, message: '缺少必要参数' });
        }

        await pool.execute(
            'INSERT INTO labs (id, name, location, device_count, remark, status) VALUES (?, ?, ?, ?, ?, ?)',
            [labId, name, location, deviceCount || 0, remark || null, 'active']
        );

        res.json({ code: 0, success: true, message: '添加成功', data: {} });
    } catch (error) {
        console.error('添加机房失败:', error);
        if (error.code === 'ER_DUP_ENTRY') {
            res.json({ code: 2002, success: false, message: '机房ID已存在' });
        } else {
            res.json({ code: 9999, success: false, message: '添加失败: ' + error.message });
        }
    }
});

// 更新机房
app.post('/api/admin/lab/update', async (req, res) => {
    try {
        const { labId, name, location, deviceCount, remark, adminKey } = req.body;

        const ADMIN_SECRET_KEY = 'YOUR_ADMIN_SECRET_KEY';
        if (adminKey !== ADMIN_SECRET_KEY) {
            return res.json({ code: 1003, success: false, message: '密钥错误，无权限操作' });
        }

        if (!labId) {
            return res.json({ code: 1001, success: false, message: '缺少机房ID' });
        }

        const [result] = await pool.execute(
            'UPDATE labs SET name = ?, location = ?, device_count = ?, remark = ? WHERE id = ?',
            [name, location, deviceCount, remark, labId]
        );

        if (result.affectedRows === 0) {
            return res.json({ code: 2001, success: false, message: '机房不存在' });
        }

        res.json({ code: 0, success: true, message: '更新成功', data: {} });
    } catch (error) {
        console.error('更新机房失败:', error);
        res.json({ code: 9999, success: false, message: '更新失败: ' + error.message });
    }
});

// 删除机房
app.post('/api/admin/lab/delete', async (req, res) => {
    try {
        const { labId, adminKey } = req.body;

        const ADMIN_SECRET_KEY = 'YOUR_ADMIN_SECRET_KEY';
        if (adminKey !== ADMIN_SECRET_KEY) {
            return res.json({ code: 1003, success: false, message: '密钥错误，无权限操作' });
        }

        if (!labId) {
            return res.json({ code: 1001, success: false, message: '缺少机房ID' });
        }

        // 检查是否有关联的报修单
        const [orders] = await pool.execute(
            'SELECT COUNT(*) as count FROM repair_orders WHERE lab_id = ?',
            [labId]
        );

        if (orders[0].count > 0) {
            return res.json({
                code: 2003,
                success: false,
                message: `该机房有 ${orders[0].count} 条报修记录，无法删除`
            });
        }

        const [result] = await pool.execute(
            'DELETE FROM labs WHERE id = ?',
            [labId]
        );

        if (result.affectedRows === 0) {
            return res.json({ code: 2001, success: false, message: '机房不存在' });
        }

        res.json({ code: 0, success: true, message: '删除成功', data: {} });
    } catch (error) {
        console.error('删除机房失败:', error);
        res.json({ code: 9999, success: false, message: '删除失败: ' + error.message });
    }
});

// 获取所有机房（包括禁用的，需要管理员密钥）
app.get('/api/admin/labs', async (req, res) => {
    try {
        const { adminKey } = req.query;

        const ADMIN_SECRET_KEY = 'YOUR_ADMIN_SECRET_KEY';
        if (adminKey !== ADMIN_SECRET_KEY) {
            return res.json({ code: 1003, success: false, message: '密钥错误，无权限操作' });
        }

        const [rows] = await pool.execute(
            'SELECT * FROM labs ORDER BY id'
        );

        res.json({ code: 0, success: true, data: { list: rows } });
    } catch (error) {
        console.error('查询机房列表失败:', error);
        res.json({ code: 9999, success: false, message: '查询失败: ' + error.message });
    }
});

// ==========================================
// 报修接口
// ==========================================

// 创建报修单
app.post('/api/repair/create', async (req, res) => {
    const connection = await pool.getConnection();

    try {
        await connection.beginTransaction();

        const {
            labId, labName, deviceType, deviceTypeName,
            faultType, faultTypeName, description,
            images, remark, phone, openid, userInfo
        } = req.body;

        // 获取机房位置
        const [labRows] = await connection.execute(
            'SELECT location FROM labs WHERE id = ?',
            [labId]
        );
        const labLocation = labRows.length > 0 ? labRows[0].location : '';

        // 如果没有传入用户信息，尝试从数据库获取
        let dbUserInfo = {};
        if (!userInfo || !userInfo.nickName) {
            const [userRows] = await connection.execute(
                'SELECT nickname, avatar FROM users WHERE openid = ?',
                [openid]
            );
            if (userRows.length > 0) {
                dbUserInfo = {
                    nickName: userRows[0].nickname,
                    avatarUrl: userRows[0].avatar
                };
            }
        }

        const finalUserInfo = userInfo && userInfo.nickName ? userInfo : dbUserInfo;

        // 插入报修单
        const [result] = await connection.execute(
            `INSERT INTO repair_orders (
        lab_id, lab_name, lab_location, device_type, device_type_name,
        fault_type, fault_type_name, description, images, remark,
        openid, user_name, user_avatar, phone, status
      ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
            [
                labId, labName, labLocation, deviceType, deviceTypeName,
                faultType, faultTypeName, description, JSON.stringify(images || []),
                remark, openid, finalUserInfo.nickName || '微信用户', finalUserInfo.avatarUrl || '', phone, 'pending'
            ]
        );

        const orderId = result.insertId;

        // 记录操作日志
        await connection.execute(
            'INSERT INTO repair_logs (order_id, action) VALUES (?, ?)',
            [orderId, '创建工单']
        );

        await connection.commit();

        res.json({
            code: 0,
            success: true,
            data: { orderId, orderNumber: orderId }
        });

        // 发送订阅消息给用户（异步，不阻塞响应）
        try {
            const wechatNotify = require('./wechat-notify.js');
            wechatNotify.sendRepairSubmitNotice(openid, labName, faultTypeName, orderId).catch(err => {
                console.error('发送报修通知失败:', err);
            });

            // 发送通知给所有管理员
            (async () => {
                try {
                    // 查询所有管理员的openid
                    const [admins] = await pool.execute(
                        "SELECT openid FROM users WHERE role='admin' AND openid IS NOT NULL"
                    );

                    if (admins.length > 0) {
                        const now = new Date();
                        const submitTime = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')} ${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}:${String(now.getSeconds()).padStart(2, '0')}`;
                        const deviceInfo = `${labName}-${deviceTypeName}`;
                        const userName = finalUserInfo.nickName || '微信用户';

                        // 批量发送给所有管理员
                        for (const admin of admins) {
                            wechatNotify.sendAdminRepairNotify(
                                admin.openid,
                                orderId,
                                userName,
                                submitTime,
                                deviceInfo,
                                description
                            ).catch(err => {
                                console.error(`发送管理员通知失败 (${admin.openid}):`, err);
                            });
                        }
                        console.log(`已向 ${admins.length} 位管理员发送报修通知`);
                    }
                } catch (err) {
                    console.error('查询管理员或发送通知失败:', err);
                }
            })();
        } catch (err) {
            console.error('加载消息通知模块失败:', err);
        }

    } catch (error) {
        await connection.rollback();
        console.error('创建报修单失败:', error);
        res.json({ code: 9999, success: false, message: '创建失败' });
    } finally {
        connection.release();
    }
});

// 获取报修单列表
app.get('/api/repair/list', async (req, res) => {
    try {
        const { openid, isAdmin: isAdminParam, status, page = 1, pageSize = 10, adminKey } = req.query;

        let sql = `SELECT r.*, 
                   r.lab_name as labName, r.lab_location as labLocation,
                   r.device_type_name as deviceTypeName, r.fault_type_name as faultTypeName,
                   COALESCE(u.nickname, r.user_name, '未命名用户') as userName, u.avatar as userAvatar 
                   FROM repair_orders r 
                   LEFT JOIN users u ON r.openid COLLATE utf8mb4_unicode_ci = u.openid COLLATE utf8mb4_unicode_ci 
                   WHERE 1=1`;
        const params = [];

        // 检查管理员密钥 - 如果提供了正确的密钥，直接返回所有工单
        const ADMIN_SECRET_KEY = 'YOUR_ADMIN_SECRET_KEY';
        const isAdminKeyValid = adminKey === ADMIN_SECRET_KEY;

        if (!isAdminKeyValid && openid) {
            // 权限控制 - 四角色系统
            // 1. 获取用户真实角色和管理员状态
            const [userRows] = await pool.execute('SELECT role, is_admin FROM users WHERE openid = ?', [openid]);
            const userRole = userRows.length > 0 ? userRows[0].role : 'user';
            const isAdmin = userRows.length > 0 && userRows[0].is_admin === 1;

            // 2. 根据角色和管理员状态过滤工单
            // 管理员（is_admin=1）或 role='admin' 或 role='teacher'：能看所有工单
            const canViewAll = isAdmin || userRole === 'admin' || userRole === 'teacher';

            if (!canViewAll) {
                if (userRole === 'student') {
                    // 学生：能看自己报修的 + 指派给自己的
                    sql += ' AND (r.openid = ? OR r.assigned_to = ?)';
                    params.push(openid, openid);
                } else {
                    // 普通用户：只能看自己报修的
                    sql += ' AND r.openid = ?';
                    params.push(openid);
                }
            }
        }
        // 如果isAdminKeyValid为true，不添加任何WHERE条件，返回所有工单

        // 状态筛选
        if (status) {
            sql += ' AND r.status = ?';
            params.push(status);
        }

        sql += ' ORDER BY r.created_at DESC LIMIT ? OFFSET ?';
        params.push(parseInt(pageSize), (parseInt(page) - 1) * parseInt(pageSize));

        const [rows] = await pool.execute(sql, params);

        // 解析图片JSON
        rows.forEach(row => {
            if (row.images) {
                row.images = JSON.parse(row.images);
            }
        });

        res.json({ code: 0, success: true, data: { list: rows } });
    } catch (error) {
        console.error('查询报修单列表失败:', error);
        res.json({ code: 9999, success: false, message: '查询失败' });
    }
});

// 获取报修单详情
app.get('/api/repair/detail', async (req, res) => {
    try {
        const { orderId } = req.query;

        const [orderRows] = await pool.execute(
            `SELECT r.*, 
             r.lab_name as labName, r.lab_location as labLocation,
             r.device_type_name as deviceTypeName, r.fault_type_name as faultTypeName,
             COALESCE(u.nickname, r.user_name, '未命名用户') as userName, 
             u.avatar as userAvatar,
             assigned_user.nickname as adminName
             FROM repair_orders r 
             LEFT JOIN users u ON r.openid COLLATE utf8mb4_unicode_ci = u.openid COLLATE utf8mb4_unicode_ci 
             LEFT JOIN users assigned_user ON r.assigned_to COLLATE utf8mb4_unicode_ci = assigned_user.openid COLLATE utf8mb4_unicode_ci
             WHERE r.id = ?`,
            [orderId]
        );

        if (orderRows.length === 0) {
            return res.json({ code: 2001, success: false, message: '工单不存在' });
        }

        const order = orderRows[0];

        // 解析图片JSON
        if (order.images) {
            order.images = JSON.parse(order.images);
        }

        // 获取处理记录
        const [logRows] = await pool.execute(
            'SELECT * FROM repair_logs WHERE order_id = ? ORDER BY created_at ASC',
            [orderId]
        );

        order.logs = logRows;

        // 获取已使用备件
        const [partRows] = await pool.execute(
            `SELECT rsp.*, sp.name, sp.part_code 
             FROM repair_spare_parts rsp
             LEFT JOIN spare_parts sp ON rsp.part_id = sp.id
             WHERE rsp.repair_order_id = ?`,
            [orderId]
        );

        order.spareParts = partRows;

        res.json({ code: 0, success: true, data: order });
    } catch (error) {
        console.error('查询报修单详情失败:', error);
        res.json({ code: 9999, success: false, message: '查询失败' });
    }
});

// 更新报修单
app.post('/api/repair/update', async (req, res) => {
    const connection = await pool.getConnection();

    try {
        await connection.beginTransaction();

        const { orderId, status, feedback, adminOpenid, adminName } = req.body;

        // 更新工单
        await connection.execute(
            'UPDATE repair_orders SET status = ?, feedback = ?, admin_openid = ?, admin_name = ? WHERE id = ?',
            [status, feedback, adminOpenid, adminName, orderId]
        );

        // 记录操作日志
        const actionMap = {
            'processing': '开始处理',
            'completed': '处理完成',
            'rejected': '拒绝处理'
        };

        await connection.execute(
            'INSERT INTO repair_logs (order_id, admin_openid, admin_name, action, remark) VALUES (?, ?, ?, ?, ?)',
            [orderId, adminOpenid, adminName, actionMap[status] || '更新状态', feedback]
        );

        await connection.commit();

        res.json({ code: 0, success: true, data: {} });

        // 发送订阅消息给用户（异步，不阻塞响应）
        try {
            const wechatNotify = require('./wechat-notify.js');
            const [orderInfo] = await pool.execute(
                'SELECT openid, lab_name FROM repair_orders WHERE id = ?',
                [orderId]
            );

            if (orderInfo.length > 0) {
                const { openid, lab_name } = orderInfo[0];

                if (status === 'processing') {
                    // 接单通知
                    wechatNotify.sendRepairAcceptNotice(openid, lab_name, adminName, orderId).catch(err => {
                        console.error('发送接单通知失败:', err);
                    });
                } else if (status === 'completed') {
                    // 完成通知
                    wechatNotify.sendRepairCompleteNotice(openid, lab_name, feedback, orderId).catch(err => {
                        console.error('发送完成通知失败:', err);
                    });
                }
            }
        } catch (err) {
            console.error('发送维修通知异常:', err);
        }

    } catch (error) {
        await connection.rollback();
        console.error('更新报修单失败:', error);
        res.json({ code: 9999, success: false, message: '更新失败' });
    } finally {
        connection.release();
    }
});

// 获取统计数据
app.get('/api/repair/stats', async (req, res) => {
    try {
        const [rows] = await pool.execute(`
      SELECT 
        COUNT(CASE WHEN status = 'pending' THEN 1 END) as pending,
        COUNT(CASE WHEN status = 'processing' THEN 1 END) as processing,
        COUNT(CASE WHEN DATE(created_at) = CURDATE() THEN 1 END) as today,
        COUNT(*) as total
      FROM repair_orders
    `);

        res.json({ code: 0, success: true, data: rows[0] });
    } catch (error) {
        console.error('查询统计数据失败:', error);
        res.json({ code: 9999, success: false, message: '查询失败' });
    }
});

// ==========================================
// 文件上传
// ==========================================

// 配置文件上传
const storage = multer.diskStorage({
    destination: function (req, file, cb) {
        const uploadDir = path.join(__dirname, 'uploads', new Date().toISOString().split('T')[0]);

        // 创建目录
        if (!fs.existsSync(uploadDir)) {
            fs.mkdirSync(uploadDir, { recursive: true });
        }

        cb(null, uploadDir);
    },
    filename: function (req, file, cb) {
        const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
        cb(null, uniqueSuffix + path.extname(file.originalname));
    }
});

const upload = multer({
    storage: storage,
    limits: { fileSize: 10 * 1024 * 1024 }, // 10MB
    fileFilter: function (req, file, cb) {
        const allowedTypes = /jpeg|jpg|png|gif/;
        const extname = allowedTypes.test(path.extname(file.originalname).toLowerCase());
        const mimetype = allowedTypes.test(file.mimetype);

        if (mimetype && extname) {
            return cb(null, true);
        } else {
            cb(new Error('只支持图片格式'));
        }
    }
});

// 上传接口
app.post('/api/upload', upload.single('file'), (req, res) => {
    try {
        if (!req.file) {
            return res.json({ code: 3001, success: false, message: '文件上传失败' });
        }

        const url = `https://你的域名/uploads/${req.file.filename}`;

        res.json({
            code: 0,
            success: true,
            data: {
                url: url,
                filename: req.file.originalname,
                size: req.file.size
            }
        });
    } catch (error) {
        console.error('文件上传失败:', error);
        res.json({ code: 9999, success: false, message: '上传失败' });
    }
});

// ==========================================
// 固定资产管理API接口
// ==========================================

// 获取资产分类列表
app.get('/api/asset/categories', async (req, res) => {
    try {
        const [rows] = await pool.execute('SELECT * FROM asset_categories ORDER BY parent_id, sort_order');
        res.json({ code: 0, success: true, data: { list: rows } });
    } catch (error) {
        console.error('获取分类失败:', error);
        res.json({ code: 9999, success: false, message: '查询失败' });
    }
});

// 获取资产列表
app.get('/api/assets', async (req, res) => {
    try {
        const { labId, categoryId, status, keyword, page = 1, pageSize = 20 } = req.query;
        let sql = 'SELECT a.*, c.name as category_name, l.name as lab_name FROM assets a LEFT JOIN asset_categories c ON a.category_id = c.id LEFT JOIN labs l ON a.lab_id COLLATE utf8mb4_unicode_ci = l.id COLLATE utf8mb4_unicode_ci WHERE 1=1';
        const params = [];
        if (labId) { sql += ' AND a.lab_id = ?'; params.push(labId); }
        if (categoryId) { sql += ' AND a.category_id = ?'; params.push(categoryId); }
        if (status) { sql += ' AND a.status = ?'; params.push(status); }
        if (keyword) { sql += ' AND (a.asset_code LIKE ? OR a.name LIKE ?)'; params.push(`%${keyword}%`, `%${keyword}%`); }
        sql += ' ORDER BY a.created_at DESC LIMIT ? OFFSET ?';
        params.push(parseInt(pageSize), (parseInt(page) - 1) * parseInt(pageSize));
        const [rows] = await pool.execute(sql, params);
        res.json({ code: 0, success: true, data: { list: rows } });
    } catch (error) {
        console.error('获取资产列表失败:', error);
        res.json({ code: 9999, success: false, message: '查询失败' });
    }
});

// 获取借用记录列表（必须在 /api/asset/:id 之前）
app.get('/api/asset/loans', async (req, res) => {
    try {
        const { status, borrower, assetId, page = 1, pageSize = 20 } = req.query;
        let sql = `SELECT al.*, a.asset_code, a.name as asset_name, a.brand, a.model
                   FROM asset_loans al
                   LEFT JOIN assets a ON al.asset_id = a.id
                   WHERE 1=1`;
        const params = [];
        if (status) { sql += ' AND al.status = ?'; params.push(status); }
        if (borrower) { sql += ' AND al.borrower_openid = ?'; params.push(borrower); }
        if (assetId) { sql += ' AND al.asset_id = ?'; params.push(assetId); }
        sql += ' ORDER BY al.created_at DESC LIMIT ? OFFSET ?';
        params.push(parseInt(pageSize), (parseInt(page) - 1) * parseInt(pageSize));
        const [rows] = await pool.execute(sql, params);
        res.json({ code: 0, success: true, data: { list: rows } });
    } catch (error) {
        console.error('获取借用记录失败:', error);
        res.json({ code: 9999, success: false, message: '查询失败' });
    }
});

// 获取资产详情（必须在 /api/asset/loans 之后）
app.get('/api/asset/:id', async (req, res) => {
    try {
        const { id } = req.params;
        const [rows] = await pool.execute(
            `SELECT a.*, c.name as category_name, l.name as lab_name FROM assets a 
             LEFT JOIN asset_categories c ON a.category_id = c.id 
             LEFT JOIN labs l ON a.lab_id COLLATE utf8mb4_unicode_ci = l.id COLLATE utf8mb4_unicode_ci 
             WHERE a.id = ?`,
            [id]
        );
        if (rows.length === 0) return res.json({ code: 2001, success: false, message: '资产不存在' });
        const [repairs] = await pool.execute('SELECT * FROM repair_orders WHERE asset_id = ? ORDER BY created_at DESC', [id]);
        res.json({ code: 0, success: true, data: { ...rows[0], repairHistory: repairs } });
    } catch (error) {
        console.error('获取资产详情失败:', error);
        res.json({ code: 9999, success: false, message: '查询失败' });
    }
});

// 添加资产（管理员）
app.post('/api/admin/asset/add', async (req, res) => {
    try {
        const { assetCode, name, categoryId, brand, model, specs, labId, location, purchaseDate, purchasePrice, supplier, warrantyPeriod, remark, adminKey } = req.body;
        const ADMIN_SECRET_KEY = 'YOUR_ADMIN_SECRET_KEY';
        if (adminKey !== ADMIN_SECRET_KEY) return res.json({ code: 1003, success: false, message: '密钥错误' });
        if (!assetCode || !name) return res.json({ code: 1001, success: false, message: '缺少必要参数' });

        let warrantyExpire = null;
        if (purchaseDate && warrantyPeriod) {
            const date = new Date(purchaseDate);
            date.setMonth(date.getMonth() + parseInt(warrantyPeriod));
            warrantyExpire = date.toISOString().split('T')[0];
        }
        await pool.execute(
            `INSERT INTO assets (asset_code, name, category_id, brand, model, specs, lab_id, location, purchase_date, purchase_price, supplier, warranty_period, warranty_expire, remark)
             VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
            [assetCode, name, categoryId || null, brand || null, model || null, specs || null, labId || null, location || null, purchaseDate || null, purchasePrice || null, supplier || null, warrantyPeriod || null, warrantyExpire, remark || null]
        );
        res.json({ code: 0, success: true, message: '添加成功' });
    } catch (error) {
        console.error('添加资产失败:', error);
        if (error.code === 'ER_DUP_ENTRY') return res.json({ code: 2002, success: false, message: '资产编号已存在' });
        res.json({ code: 9999, success: false, message: '添加失败' });
    }
});

// 资产统计
app.get('/api/asset/stats', async (req, res) => {
    try {
        // 先查询总数
        const [countResult] = await pool.execute('SELECT COUNT(*) as totalCount FROM assets');

        // 尝试按状态统计（如果status字段存在）
        let inUseCount = 0, idleCount = 0, repairingCount = 0;
        try {
            const [statusResult] = await pool.execute(`
                SELECT 
                    SUM(CASE WHEN status = 'in_use' THEN 1 ELSE 0 END) as inUseCount,
                    SUM(CASE WHEN status = 'idle' THEN 1 ELSE 0 END) as idleCount,
                    SUM(CASE WHEN status = 'repairing' THEN 1 ELSE 0 END) as repairingCount
                FROM assets
            `);
            inUseCount = statusResult[0].inUseCount || 0;
            idleCount = statusResult[0].idleCount || 0;
            repairingCount = statusResult[0].repairingCount || 0;
        } catch (err) {
            // status字段不存在时，使用默认值
            console.log('status字段查询失败，使用默认值');
        }

        res.json({
            code: 0,
            success: true,
            data: {
                totalCount: countResult[0].totalCount,
                inUseCount: inUseCount,
                idleCount: idleCount,
                repairingCount: repairingCount
            }
        });
    } catch (error) {
        console.error('获取统计失败:', error);
        res.json({ code: 9999, success: false, message: '查询失败: ' + error.message });
    }
});

// ==========================================
// 备件库管理API
// ==========================================

// 添加备件（管理员）
app.post('/api/admin/spare-part/add', async (req, res) => {
    try {
        const { partCode, name, category, brand, model, specifications, unit, unitPrice, minStock, location, remark, adminKey } = req.body;
        const ADMIN_SECRET_KEY = 'YOUR_ADMIN_SECRET_KEY';
        if (adminKey !== ADMIN_SECRET_KEY) return res.json({ code: 1003, success: false, message: '密钥错误' });
        if (!partCode || !name) return res.json({ code: 1001, success: false, message: '备件编号和名称为必填项' });

        const [result] = await pool.execute(
            `INSERT INTO spare_parts (part_code, name, category, brand, model, specifications, unit, unit_price, min_stock, location, remark)
             VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
            [partCode, name, category, brand, model, specifications, unit || '个', unitPrice, minStock || 0, location, remark]
        );
        res.json({ code: 0, success: true, message: '添加成功', data: { id: result.insertId } });
    } catch (error) {
        console.error('添加备件失败:', error);
        if (error.code === 'ER_DUP_ENTRY') return res.json({ code: 2001, success: false, message: '备件编号已存在' });
        res.json({ code: 9999, success: false, message: '添加失败' });
    }
});

// 备件列表
app.get('/api/spare-parts', async (req, res) => {
    try {
        const { keyword, category, lowStock, page = 1, pageSize = 20 } = req.query;
        let sql = 'SELECT * FROM spare_parts WHERE 1=1';
        const params = [];
        if (keyword) { sql += ' AND (part_code LIKE ? OR name LIKE ?)'; params.push(`%${keyword}%`, `%${keyword}%`); }
        if (category) { sql += ' AND category = ?'; params.push(category); }
        if (lowStock === 'true') sql += ' AND current_stock < min_stock';
        sql += ' ORDER BY created_at DESC LIMIT ? OFFSET ?';
        params.push(parseInt(pageSize), (parseInt(page) - 1) * parseInt(pageSize));
        const [rows] = await pool.execute(sql, params);
        res.json({ code: 0, success: true, data: { list: rows } });
    } catch (error) {
        console.error('查询备件失败:', error);
        res.json({ code: 9999, success: false, message: '查询失败' });
    }
});

// 入库（管理员）
app.post('/api/admin/spare-part/stock-in', async (req, res) => {
    const connection = await pool.getConnection();
    try {
        await connection.beginTransaction();
        const { partId, quantity, unitPrice, operatorOpenid, operatorName, remark, adminKey } = req.body;
        const ADMIN_SECRET_KEY = 'YOUR_ADMIN_SECRET_KEY';
        if (adminKey !== ADMIN_SECRET_KEY) return res.json({ code: 1003, success: false, message: '密钥错误' });
        if (!partId || !quantity) return res.json({ code: 1001, success: false, message: '缺少必要参数' });

        const totalPrice = unitPrice ? (unitPrice * quantity) : null;
        await connection.execute(
            `INSERT INTO spare_part_stock (part_id, type, quantity, unit_price, total_price, operator_openid, operator_name, remark)
             VALUES (?, 'in', ?, ?, ?, ?, ?, ?)`,
            [partId, quantity, unitPrice, totalPrice, operatorOpenid, operatorName, remark]
        );
        await connection.execute('UPDATE spare_parts SET current_stock = current_stock + ? WHERE id = ?', [quantity, partId]);
        await connection.commit();
        res.json({ code: 0, success: true, message: '入库成功' });
    } catch (error) {
        await connection.rollback();
        console.error('入库失败:', error);
        res.json({ code: 9999, success: false, message: '入库失败' });
    } finally {
        connection.release();
    }
});

// 出库（管理员）
app.post('/api/admin/spare-part/stock-out', async (req, res) => {
    const connection = await pool.getConnection();
    try {
        await connection.beginTransaction();
        const { partId, quantity, repairOrderId, operatorOpenid, operatorName, remark, adminKey } = req.body;
        const ADMIN_SECRET_KEY = 'YOUR_ADMIN_SECRET_KEY';
        if (adminKey !== ADMIN_SECRET_KEY) return res.json({ code: 1003, success: false, message: '密钥错误' });
        if (!partId || !quantity) return res.json({ code: 1001, success: false, message: '缺少必要参数' });

        const [parts] = await connection.execute('SELECT current_stock, unit_price FROM spare_parts WHERE id = ?', [partId]);
        if (parts.length === 0) { await connection.rollback(); return res.json({ code: 2001, success: false, message: '备件不存在' }); }
        if (parts[0].current_stock < quantity) { await connection.rollback(); return res.json({ code: 2002, success: false, message: '库存不足' }); }

        const unitPrice = parts[0].unit_price;
        const totalPrice = unitPrice ? (unitPrice * quantity) : null;
        await connection.execute(
            `INSERT INTO spare_part_stock (part_id, type, quantity, unit_price, total_price, repair_order_id, operator_openid, operator_name, remark)
             VALUES (?, 'out', ?, ?, ?, ?, ?, ?, ?)`,
            [partId, quantity, unitPrice, totalPrice, repairOrderId, operatorOpenid, operatorName, remark]
        );
        await connection.execute('UPDATE spare_parts SET current_stock = current_stock - ? WHERE id = ?', [quantity, partId]);
        await connection.commit();
        res.json({ code: 0, success: true, message: '出库成功' });
    } catch (error) {
        await connection.rollback();
        console.error('出库失败:', error);
        res.json({ code: 9999, success: false, message: '出库失败' });
    } finally {
        connection.release();
    }
});

// 维修单使用备件
app.post('/api/repair/use-spare-part', async (req, res) => {
    const connection = await pool.getConnection();
    try {
        await connection.beginTransaction();
        const { repairOrderId, partId, quantity, operatorOpenid, operatorName } = req.body;
        if (!repairOrderId || !partId || !quantity) return res.json({ code: 1001, success: false, message: '缺少必要参数' });

        const [parts] = await connection.execute('SELECT current_stock, unit_price FROM spare_parts WHERE id = ?', [partId]);
        if (parts.length === 0) { await connection.rollback(); return res.json({ code: 2001, success: false, message: '备件不存在' }); }
        if (parts[0].current_stock < quantity) { await connection.rollback(); return res.json({ code: 2002, success: false, message: '库存不足' }); }

        const unitPrice = parts[0].unit_price;
        const totalPrice = unitPrice ? (unitPrice * quantity) : null; // 插入使用记录
        const [result] = await connection.execute(
            `INSERT INTO repair_spare_parts (repair_order_id, part_id, quantity, unit_price, total_price)
             VALUES (?, ?, ?, ?, ?)`,
            [repairOrderId, partId, quantity, unitPrice, totalPrice]
        );

        // 插入出库记录
        await connection.execute(
            `INSERT INTO spare_part_stock (part_id, type, quantity, unit_price, total_price, repair_order_id, operator_openid, operator_name, remark)
             VALUES (?, 'out', ?, ?, ?, ?, ?, ?, '维修单使用')`,
            [partId, quantity, unitPrice, totalPrice, repairOrderId, operatorOpenid, operatorName]
        );

        // 更新库存
        await connection.execute(
            'UPDATE spare_parts SET current_stock = current_stock - ? WHERE id = ?',
            [quantity, partId]
        );

        await connection.commit();

        res.json({ code: 0, success: true, message: '使用备件成功', data: { id: result.insertId } });
    } catch (error) {
        await connection.rollback();
        console.error('使用备件失败:', error);
        res.json({ code: 9999, success: false, message: '使用失败' });
    } finally {
        connection.release();
    }
});

// 移除维修单备件
app.post('/api/repair/remove-spare-part', async (req, res) => {
    const connection = await pool.getConnection();

    try {
        await connection.beginTransaction();

        const { repairOrderId, partId, adminKey } = req.body;

        const ADMIN_SECRET_KEY = 'YOUR_ADMIN_SECRET_KEY';
        if (adminKey !== ADMIN_SECRET_KEY) {
            return res.json({ code: 1003, success: false, message: '密钥错误' });
        }

        // 查询记录是否存在
        const [rows] = await connection.execute(
            'SELECT * FROM repair_spare_parts WHERE id = ? AND repair_order_id = ?',
            [partId, repairOrderId]
        );

        if (rows.length === 0) {
            await connection.rollback();
            return res.json({ code: 2001, success: false, message: '记录不存在' });
        }

        const record = rows[0];

        // 恢复库存
        await connection.execute(
            'UPDATE spare_parts SET current_stock = current_stock + ? WHERE id = ?',
            [record.quantity, record.part_id]
        );

        // 插入入库记录（恢复）
        await connection.execute(
            `INSERT INTO spare_part_stock (part_id, type, quantity, unit_price, total_price, repair_order_id, remark)
             VALUES (?, 'in', ?, ?, ?, ?, '移除备件恢复库存')`,
            [record.part_id, record.quantity, record.unit_price, record.total_price, repairOrderId]
        );

        // 删除使用记录
        await connection.execute('DELETE FROM repair_spare_parts WHERE id = ?', [partId]);

        await connection.commit();

        res.json({ code: 0, success: true, message: '移除成功' });
    } catch (error) {
        await connection.rollback();
        console.error('移除备件失败:', error);
        res.json({ code: 9999, success: false, message: '移除失败' });
    } finally {
        connection.release();
    }
});

// 备件统计
app.get('/api/admin/spare-parts/stats', async (req, res) => {
    try {
        const { adminKey } = req.query;
        const ADMIN_SECRET_KEY = 'YOUR_ADMIN_SECRET_KEY';
        if (adminKey !== ADMIN_SECRET_KEY) return res.json({ code: 1003, success: false, message: '密钥错误' });

        const [total] = await pool.execute('SELECT COUNT(*) as count FROM spare_parts');
        const [lowStock] = await pool.execute('SELECT COUNT(*) as count FROM spare_parts WHERE current_stock < min_stock');
        const [totalValue] = await pool.execute('SELECT SUM(current_stock * unit_price) as value FROM spare_parts');
        res.json({ code: 0, success: true, data: { totalCount: total[0].count, lowStockCount: lowStock[0].count, totalValue: totalValue[0].value || 0 } });
    } catch (error) {
        console.error('统计失败:', error);
        res.json({ code: 9999, success: false, message: '统计失败' });
    }
});

// ==========================================
// 资产借用管理API
// ==========================================

// 申请借用资产
app.post('/api/asset/loan/apply', async (req, res) => {
    try {
        const { assetId, purpose, expectedReturnDate, openid, userInfo } = req.body;
        if (!assetId || !purpose || !expectedReturnDate) {
            return res.json({ code: 1001, success: false, message: '缺少必要参数' });
        }

        // 检查资产是否存在且可借用
        const [assets] = await pool.execute('SELECT * FROM assets WHERE id = ?', [assetId]);
        if (assets.length === 0) {
            return res.json({ code: 2001, success: false, message: '资产不存在' });
        }

        // 创建借用申请
        const [result] = await pool.execute(
            `INSERT INTO asset_loans (asset_id, borrower_openid, borrower_name, purpose, expected_return_date, status)
             VALUES (?, ?, ?, ?, ?, 'pending')`,
            [assetId, openid, userInfo?.nickName || '用户', purpose, expectedReturnDate]
        );

        res.json({ code: 0, success: true, message: '申请成功，等待审批', data: { loanId: result.insertId } });

        // 发送订阅消息通知（异步，不阻塞响应）
        try {
            const wechatNotify = require('./wechat-notify.js');
            const assetName = assets[0].name;
            wechatNotify.sendLoanApplyNotice(openid, assetName, expectedReturnDate).catch(err => {
                console.error('发送申请通知失败:', err);
            });
        } catch (err) {
            console.error('加载消息通知模块失败:', err);
        }
    } catch (error) {
        console.error('申请借用失败:', error);
        res.json({ code: 9999, success: false, message: '申请失败' });
    }
});

// 获取我的借用记录
app.get('/api/my-loans', async (req, res) => {
    try {
        const { openid, status, page = 1, pageSize = 20 } = req.query;

        if (!openid) {
            return res.json({ code: 1001, success: false, message: '缺少用户openid' });
        }

        let sql = `SELECT al.*, a.asset_code, a.name as asset_name, a.brand, a.model
                   FROM asset_loans al
                   LEFT JOIN assets a ON al.asset_id = a.id
                   WHERE al.borrower_openid = ?`;
        const params = [openid];

        if (status) {
            sql += ' AND al.status = ?';
            params.push(status);
        }

        sql += ' ORDER BY al.created_at DESC LIMIT ? OFFSET ?';
        params.push(parseInt(pageSize), (parseInt(page) - 1) * parseInt(pageSize));

        const [rows] = await pool.execute(sql, params);

        res.json({ code: 0, success: true, data: { list: rows } });
    } catch (error) {
        console.error('获取我的借用记录失败:', error);
        res.json({ code: 9999, success: false, message: '查询失败' });
    }
});

// 审批借用（管理员）
app.post('/api/admin/asset/loan/approve', async (req, res) => {
    const connection = await pool.getConnection();
    try {
        await connection.beginTransaction();
        const { loanId, approve, rejectReason, adminOpenid, adminName, adminKey } = req.body;
        const ADMIN_SECRET_KEY = 'YOUR_ADMIN_SECRET_KEY';
        if (adminKey !== ADMIN_SECRET_KEY) return res.json({ code: 1003, success: false, message: '密钥错误' });
        if (!loanId || approve === undefined) return res.json({ code: 1001, success: false, message: '缺少必要参数' });

        const [loans] = await connection.execute('SELECT * FROM asset_loans WHERE id = ? AND status = "pending"', [loanId]);
        if (loans.length === 0) { await connection.rollback(); return res.json({ code: 2001, success: false, message: '借用记录不存在或已处理' }); }

        const loan = loans[0];
        const newStatus = approve ? 'approved' : 'rejected';
        await connection.execute(
            `UPDATE asset_loans SET status = ?, approver_openid = ?, approver_name = ?, approve_time = NOW(), reject_reason = ? WHERE id = ?`,
            [newStatus, adminOpenid, adminName, rejectReason, loanId]
        );
        if (approve) {
            await connection.execute('UPDATE assets SET current_loan_id = ?, status = "in_use" WHERE id = ?', [loanId, loan.asset_id]);
        }
        await connection.commit();

        res.json({ code: 0, success: true, message: approve ? '已批准' : '已拒绝' });

        // 发送订阅消息通知
        try {
            const wechatNotify = require('./wechat-notify.js');
            const [assetInfo] = await connection.execute('SELECT name FROM assets WHERE id = ?', [loan.asset_id]);
            const assetName = assetInfo[0]?.name || '资产';
            wechatNotify.sendLoanApproveNotice(loan.borrower_openid, assetName, approve, rejectReason).catch(err => {
                console.error('发送审批通知失败:', err);
            });
        } catch (err) {
            console.error('发送审批通知异常:', err);
        }
    } catch (error) {
        await connection.rollback();
        console.error('审批失败:', error);
        res.json({ code: 9999, success: false, message: '审批失败' });
    } finally {
        connection.release();
    }
});

// 用户归还借用资产
app.post('/api/asset/loan/return', async (req, res) => {
    const connection = await pool.getConnection();
    try {
        await connection.beginTransaction();

        const { loanId, returnCondition, openid } = req.body;
        if (!loanId || !openid) {
            return res.json({ code: 1001, success: false, message: '缺少必要参数' });
        }

        // 验证借用记录是否存在且属于该用户
        const [loans] = await connection.execute(
            'SELECT * FROM asset_loans WHERE id = ? AND borrower_openid = ? AND status = "approved"',
            [loanId, openid]
        );

        if (loans.length === 0) {
            await connection.rollback();
            return res.json({ code: 2001, success: false, message: '借用记录不存在或已归还' });
        }

        const loan = loans[0];

        // 更新借用记录状态为已归还
        await connection.execute(
            'UPDATE asset_loans SET status = "returned", actual_return_date = NOW(), return_condition = ? WHERE id = ?',
            [returnCondition || '正常', loanId]
        );

        // 更新资产状态为空闲
        await connection.execute(
            'UPDATE assets SET status = "idle", current_loan_id = NULL WHERE id = ?',
            [loan.asset_id]
        );

        await connection.commit();
        res.json({ code: 0, success: true, message: '归还成功' });
    } catch (error) {
        await connection.rollback();
        console.error('归还失败:', error);
        res.json({ code: 9999, success: false, message: '归还失败' });
    } finally {
        connection.release();
    }
});

// ==========================================
// 系统配置管理API
// ==========================================

// 获取系统配置
app.get('/api/admin/config', async (req, res) => {
    try {
        const { adminKey, group } = req.query;
        const ADMIN_SECRET_KEY = 'YOUR_ADMIN_SECRET_KEY';
        if (adminKey !== ADMIN_SECRET_KEY) return res.json({ code: 1003, success: false, message: '密钥错误' });

        let sql = 'SELECT config_key, config_value, description FROM system_config WHERE 1=1';
        const params = [];

        if (group) {
            sql += ' AND config_group = ?';
            params.push(group);
        }

        sql += ' ORDER BY config_group, id';

        const [rows] = await pool.execute(sql, params);

        // 转换为键值对格式
        const config = {};
        rows.forEach(row => {
            config[row.config_key] = {
                value: row.config_value,
                description: row.description
            };
        });

        res.json({ code: 0, success: true, data: config });
    } catch (error) {
        console.error('获取配置失败:', error);
        res.json({ code: 9999, success: false, message: '查询失败' });
    }
});

// 获取微信订阅消息模板ID（公开接口，供小程序使用）
app.get('/api/wechat/template-ids', async (req, res) => {
    try {
        const [rows] = await pool.execute(
            "SELECT config_key, config_value FROM system_config WHERE config_group='wechat' AND config_key LIKE 'wechat_template_%' AND config_key NOT LIKE '%_content'"
        );

        const templates = {};
        rows.forEach(row => {
            if (row.config_value && row.config_value.trim()) {
                templates[row.config_key] = row.config_value;
            }
        });

        res.json({ code: 0, success: true, data: templates });
    } catch (error) {
        console.error('获取模板ID失败:', error);
        res.json({ code: 9999, success: false, message: '查询失败' });
    }
});

// 保存系统配置
app.post('/api/admin/config/save', async (req, res) => {
    try {
        const { adminKey, configs } = req.body;
        const ADMIN_SECRET_KEY = 'YOUR_ADMIN_SECRET_KEY';
        if (adminKey !== ADMIN_SECRET_KEY) return res.json({ code: 1003, success: false, message: '密钥错误' });
        if (!configs || typeof configs !== 'object') return res.json({ code: 1001, success: false, message: '参数错误' });

        const connection = await pool.getConnection();
        try {
            await connection.beginTransaction();

            for (const [key, value] of Object.entries(configs)) {
                // 使用 INSERT ... ON DUPLICATE KEY UPDATE 来支持新增或更新
                // 对于 _content 配置，自动设置 config_group 为 wechat
                const group = key.includes('wechat') ? 'wechat' : 'system';
                const description = key.endsWith('_content')
                    ? `${key.replace('_content', '')} 模板内容JSON`
                    : '系统配置项';

                await connection.execute(
                    `INSERT INTO system_config (config_key, config_value, config_group, description) 
                     VALUES (?, ?, ?, ?) 
                     ON DUPLICATE KEY UPDATE config_value = VALUES(config_value)`,
                    [key, value, group, description]
                );
            }

            await connection.commit();
            res.json({ code: 0, success: true, message: '保存成功' });
        } catch (err) {
            await connection.rollback();
            throw err;
        } finally {
            connection.release();
        }
    } catch (error) {
        console.error('保存配置失败:', error);
        res.json({ code: 9999, success: false, message: '保存失败' });
    }
});

// ==========================================
// Excel批量导入资产
// ==========================================

// 批量导入资产（管理员）
// Excel文件上传配置
const excelUpload = multer({
    storage: storage,
    limits: { fileSize: 10 * 1024 * 1024 }, // 10MB
    fileFilter: function (req, file, cb) {
        const allowedTypes = /xlsx|xls/;
        const extname = allowedTypes.test(path.extname(file.originalname).toLowerCase());

        // Excel mimetype check can be tricky, relying mainly on extension for now or standard excel mimes
        // const mimetype = file.mimetype === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' || file.mimetype === 'application/vnd.ms-excel';

        if (extname) {
            return cb(null, true);
        } else {
            cb(new Error('只支持Excel格式(.xlsx, .xls)'));
        }
    }
});

// 导入资产接口
app.post('/api/admin/asset/import', excelUpload.single('file'), async (req, res) => {
    const connection = await pool.getConnection();

    try {
        const { adminKey } = req.body;

        const ADMIN_SECRET_KEY = 'YOUR_ADMIN_SECRET_KEY';
        if (adminKey !== ADMIN_SECRET_KEY) {
            return res.json({ code: 1003, success: false, message: '密钥错误' });
        }

        if (!req.file) {
            return res.json({ code: 1001, success: false, message: '请上传Excel文件' });
        }

        // 动态加载xlsx模块
        let XLSX;
        try {
            XLSX = require('xlsx');
        } catch (error) {
            return res.json({ code: 9999, success: false, message: '服务器缺少xlsx模块，请先执行: npm install xlsx' });
        }

        // 读取Excel文件
        const workbook = XLSX.readFile(req.file.path);
        const sheetName = workbook.SheetNames[0];
        const worksheet = workbook.Sheets[sheetName];

        // 转换为JSON
        const data = XLSX.utils.sheet_to_json(worksheet);

        if (!data || data.length === 0) {
            return res.json({ code: 2001, success: false, message: 'Excel文件为空' });
        }

        await connection.beginTransaction();

        let successCount = 0;
        let failCount = 0;
        const errors = [];

        for (let i = 0; i < data.length; i++) {
            const row = data[i];

            try {
                // 验证必填字段
                if (!row['资产编号'] || !row['资产名称'] || !row['分类ID']) {
                    errors.push(`第${i + 2}行：缺少必填字段`);
                    failCount++;
                    continue;
                }

                // 插入资产
                await connection.execute(
                    `INSERT INTO assets (
                        asset_code, name, category_id, lab_id, brand, model, 
                        purchase_price, purchase_date, status, remark
                    ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
                    [
                        row['资产编号'],
                        row['资产名称'],
                        row['分类ID'],
                        row['机房ID'] || null,
                        row['品牌'] || null,
                        row['型号'] || null,
                        row['采购价格'] || null,
                        row['采购日期'] || null,
                        row['状态'] || 'in_use',
                        row['备注'] || null
                    ]
                );

                successCount++;
            } catch (error) {
                // 可能是重复的资产编号
                if (error.code === 'ER_DUP_ENTRY') {
                    errors.push(`第${i + 2}行：资产编号已存在`);
                } else {
                    errors.push(`第${i + 2}行：${error.message}`);
                }
                failCount++;
            }
        }

        await connection.commit();

        res.json({
            code: 0,
            success: true,
            message: '导入完成',
            data: {
                total: data.length,
                successCount,
                failCount,
                errors: errors.slice(0, 10) // 只返回前10个错误
            }
        });

    } catch (error) {
        await connection.rollback();
        console.error('批量导入失败:', error);
        res.json({ code: 9999, success: false, message: '导入失败: ' + error.message });
    } finally {
        connection.release();
    }
});

// 下载Excel模板
app.get('/api/admin/asset/template', (req, res) => {
    const { adminKey } = req.query;

    const ADMIN_SECRET_KEY = 'YOUR_ADMIN_SECRET_KEY';
    if (adminKey !== ADMIN_SECRET_KEY) {
        return res.json({ code: 1003, success: false, message: '密钥错误' });
    }

    // 动态加载xlsx模块
    let XLSX;
    try {
        XLSX = require('xlsx');
    } catch (error) {
        return res.json({ code: 9999, success: false, message: '服务器缺少xlsx模块，请先执行: npm install xlsx' });
    }

    // 创建示例数据
    const template = [
        {
            '资产编号': 'PC-A101-001',
            '资产名称': '戴尔台式电脑',
            '分类ID': 6,
            '机房ID': 'A101',
            '品牌': 'Dell',
            '型号': 'OptiPlex 7090',
            '采购价格': 4500.00,
            '采购日期': '2024-01-15',
            '状态': 'in_use',
            '备注': '示例数据，请删除此行'
        }
    ];

    // 创建工作簿
    const wb = XLSX.utils.book_new();
    const ws = XLSX.utils.json_to_sheet(template);

    // 设置列宽
    ws['!cols'] = [
        { wch: 15 }, { wch: 20 }, { wch: 10 }, { wch: 12 }, { wch: 12 },
        { wch: 15 }, { wch: 12 }, { wch: 12 }, { wch: 10 }, { wch: 20 }
    ];

    XLSX.utils.book_append_sheet(wb, ws, '资产导入模板');

    // 生成buffer
    const buffer = XLSX.write(wb, { type: 'buffer', bookType: 'xlsx' });

    res.setHeader('Content-Disposition', 'attachment; filename=asset_import_template.xlsx');
    res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
    res.send(buffer);
});

// 静态文件服务
app.use('/uploads', express.static(path.join(__dirname, 'uploads')));

// ==========================================
// 盘点和报废管理API (占位符)
// ==========================================

// 获取盘点列表
app.get('/api/inventory/list', async (req, res) => {
    res.json({ code: 0, success: true, data: { list: [] } });
});

// 获取报废申请列表
app.get('/api/asset/disposal/list', async (req, res) => {
    res.json({ code: 0, success: true, data: { list: [] } });
});

// 生成微信小程序码
app.get('/api/admin/qrcode/wxa', async (req, res) => {
    try {
        const { scene, page, width, adminKey } = req.query;

        const ADMIN_SECRET_KEY = 'YOUR_ADMIN_SECRET_KEY';
        if (adminKey !== ADMIN_SECRET_KEY) {
            return res.status(403).json({ code: 1003, success: false, message: '密钥错误' });
        }

        if (!scene) {
            return res.status(400).json({ code: 1001, success: false, message: '缺少scene参数' });
        }

        const buffer = await wechatNotify.getUnlimitedQRCode(scene, page, width);

        if (buffer) {
            res.writeHead(200, {
                'Content-Type': 'image/jpeg',
                'Content-Length': buffer.length
            });
            res.end(buffer);
        } else {
            res.status(500).json({ code: 9999, success: false, message: '生成二维码失败' });
        }
    } catch (error) {
        console.error('生成小程序码API异常:', error);
        res.status(500).json({ code: 9999, success: false, message: '服务器内部错误' });
    }
});

// ==========================================
// 删除用户API（管理员功能）
// ==========================================

// 删除用户
app.post('/api/admin/delete-user', async (req, res) => {
    const connection = await pool.getConnection();

    try {
        const { openid, adminKey } = req.body;

        // 验证管理员密钥
        const ADMIN_SECRET_KEY = 'YOUR_ADMIN_SECRET_KEY';
        if (adminKey !== ADMIN_SECRET_KEY) {
            return res.json({
                code: 1003,
                success: false,
                message: '密钥错误，无权限操作'
            });
        }

        if (!openid) {
            return res.json({
                code: 1001,
                success: false,
                message: '缺少openid参数'
            });
        }

        // 开始事务
        await connection.beginTransaction();

        try {
            // 1. 删除用户的报修工单
            await connection.execute(
                'DELETE FROM repair_orders WHERE openid = ?',
                [openid]
            );

            // 2. 删除用户的借用记录
            await connection.execute(
                'DELETE FROM asset_loans WHERE borrower_openid = ?',
                [openid]
            );

            // 3. 删除用户本身
            const [result] = await connection.execute(
                'DELETE FROM users WHERE openid = ?',
                [openid]
            );

            if (result.affectedRows === 0) {
                await connection.rollback();
                return res.json({
                    code: 2001,
                    success: false,
                    message: '用户不存在'
                });
            }

            // 提交事务
            await connection.commit();

            res.json({
                code: 0,
                success: true,
                message: '用户删除成功',
                data: { deletedOpenid: openid }
            });

        } catch (error) {
            await connection.rollback();
            throw error;
        }

    } catch (error) {
        console.error('删除用户失败:', error);
        res.json({
            code: 9999,
            success: false,
            message: '删除失败: ' + error.message
        });
    } finally {
        connection.release();
    }
});

// 批量删除用户
app.post('/api/admin/delete-users-batch', async (req, res) => {
    const connection = await pool.getConnection();

    try {
        const { openids, adminKey } = req.body;

        // 验证管理员密钥
        const ADMIN_SECRET_KEY = 'YOUR_ADMIN_SECRET_KEY';
        if (adminKey !== ADMIN_SECRET_KEY) {
            return res.json({
                code: 1003,
                success: false,
                message: '密钥错误，无权限操作'
            });
        }

        // 验证参数
        if (!openids || !Array.isArray(openids) || openids.length === 0) {
            return res.json({
                code: 1001,
                success: false,
                message: '参数错误'
            });
        }

        // 开始事务
        await connection.beginTransaction();

        try {
            let deletedCount = 0;

            for (const openid of openids) {
                // 删除报修记录
                await connection.execute(
                    'DELETE FROM repair_orders WHERE openid = ?',
                    [openid]
                );

                // 删除借用记录
                await connection.execute(
                    'DELETE FROM asset_loans WHERE borrower_openid = ?',
                    [openid]
                );

                // 删除用户
                const [result] = await connection.execute(
                    'DELETE FROM users WHERE openid = ?',
                    [openid]
                );

                if (result.affectedRows > 0) {
                    deletedCount++;
                }
            }

            // 提交事务
            await connection.commit();

            res.json({
                code: 0,
                success: true,
                message: `成功删除 ${deletedCount} 个用户`,
                data: {
                    deletedCount,
                    totalRequested: openids.length
                }
            });

        } catch (error) {
            await connection.rollback();
            throw error;
        }

    } catch (error) {
        console.error('批量删除用户失败:', error);
        res.json({
            code: 9999,
            success: false,
            message: '删除失败: ' + error.message
        });
    } finally {
        connection.release();
    }
});

// ==========================================
// 资产信息和二维码管理接口
// ==========================================

// 获取资产详细信息（用于扫码后自动填充保修单）
app.get('/api/assets/:assetId/info', async (req, res) => {
    try {
        const { assetId } = req.params;

        if (!assetId) {
            return res.json({ code: 1001, success: false, message: '缺少资产ID' });
        }

        // 查询资产详细信息
        const [rows] = await pool.execute(`
            SELECT 
                a.id,
                a.asset_code,
                a.name,
                a.brand,
                a.model,
                a.specs,
                a.lab_id,
                a.location,
                a.status,
                a.qr_code,
                l.name as lab_name,
                l.location as lab_location,
                c.name as category_name
            FROM assets a
            LEFT JOIN labs l ON a.lab_id COLLATE utf8mb4_unicode_ci = l.id COLLATE utf8mb4_unicode_ci
            LEFT JOIN asset_categories c ON a.category_id = c.id
            WHERE a.id = ?
        `, [assetId]);

        if (rows.length === 0) {
            return res.json({ code: 2001, success: false, message: '资产不存在' });
        }

        const asset = rows[0];

        // 检查资产状态
        if (asset.status === 'scrapped') {
            return res.json({
                code: 2002,
                success: false,
                message: '该设备已报废，无法提交报修'
            });
        }

        res.json({
            code: 0,
            success: true,
            data: asset
        });

    } catch (error) {
        console.error('获取资产信息失败:', error);
        res.json({ code: 9999, success: false, message: '查询失败: ' + error.message });
    }
});

// 批量生成资产二维码URL
app.post('/api/qrcode/generate-batch', async (req, res) => {
    try {
        const { assetIds, domain, adminKey } = req.body;

        // 安全密钥验证
        const ADMIN_SECRET_KEY = 'YOUR_ADMIN_SECRET_KEY';
        if (adminKey !== ADMIN_SECRET_KEY) {
            return res.json({ code: 1003, success: false, message: '密钥错误，无权限操作' });
        }

        if (!assetIds || !Array.isArray(assetIds) || assetIds.length === 0) {
            return res.json({ code: 1001, success: false, message: '缺少资产ID列表' });
        }

        if (!domain) {
            return res.json({ code: 1002, success: false, message: '缺少域名参数' });
        }

        const results = [];

        for (const assetId of assetIds) {
            // 生成二维码URL
            const qrCodeUrl = `${domain}/device/repair?assetId=${assetId}`;

            // 更新数据库中的qr_code字段
            const [result] = await pool.execute(
                'UPDATE assets SET qr_code = ? WHERE id = ?',
                [qrCodeUrl, assetId]
            );

            if (result.affectedRows > 0) {
                results.push({
                    assetId,
                    qrCodeUrl,
                    status: 'success'
                });
            } else {
                results.push({
                    assetId,
                    qrCodeUrl: null,
                    status: 'failed',
                    message: '资产不存在'
                });
            }
        }

        res.json({
            code: 0,
            success: true,
            message: '二维码生成完成',
            data: { results }
        });

    } catch (error) {
        console.error('生成二维码失败:', error);
        res.json({ code: 9999, success: false, message: '生成失败: ' + error.message });
    }
});

// 为单个资产生成二维码URL
app.post('/api/qrcode/generate', async (req, res) => {
    try {
        const { assetId, domain, adminKey } = req.body;

        // 安全密钥验证
        const ADMIN_SECRET_KEY = 'YOUR_ADMIN_SECRET_KEY';
        if (adminKey !== ADMIN_SECRET_KEY) {
            return res.json({ code: 1003, success: false, message: '密钥错误，无权限操作' });
        }

        if (!assetId) {
            return res.json({ code: 1001, success: false, message: '缺少资产ID' });
        }

        if (!domain) {
            return res.json({ code: 1002, success: false, message: '缺少域名参数' });
        }

        // 生成二维码URL
        const qrCodeUrl = `${domain}/device/repair?assetId=${assetId}`;

        // 更新数据库
        const [result] = await pool.execute(
            'UPDATE assets SET qr_code = ? WHERE id = ?',
            [qrCodeUrl, assetId]
        );

        if (result.affectedRows === 0) {
            return res.json({ code: 2001, success: false, message: '资产不存在' });
        }

        res.json({
            code: 0,
            success: true,
            message: '二维码生成成功',
            data: { assetId, qrCodeUrl }
        });

    } catch (error) {
        console.error('生成二维码失败:', error);
        res.json({ code: 9999, success: false, message: '生成失败: ' + error.message });
    }
});

// 获取资产的二维码信息
app.get('/api/qrcode/asset/:assetId', async (req, res) => {
    try {
        const { assetId } = req.params;

        if (!assetId) {
            return res.json({ code: 1001, success: false, message: '缺少资产ID' });
        }

        const [rows] = await pool.execute(
            'SELECT id, asset_code, name, qr_code FROM assets WHERE id = ?',
            [assetId]
        );

        if (rows.length === 0) {
            return res.json({ code: 2001, success: false, message: '资产不存在' });
        }

        res.json({
            code: 0,
            success: true,
            data: rows[0]
        });

    } catch (error) {
        console.error('获取二维码信息失败:', error);
        res.json({ code: 9999, success: false, message: '查询失败: ' + error.message });
    }
});

// 启动服务器
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
    console.log(`Server is running on port ${PORT}`);
});

// ==========================================
// 注意事项
// ==========================================

// 1. 需要安装依赖：npm install express mysql2 axios multer
// 2. 需要配置微信小程序 AppID 和 AppSecret
// 3. 需要配置数据库连接信息
// 4. 生产环境建议：
//    - 使用 JWT 进行身份认证
//    - 添加请求频率限制
//    - 使用 HTTPS
//    - 完善错误处理和日志记录
//    - 使用云存储服务（如腾讯云COS）存储图片
//    - 使用 PM2 进行进程管理
//    - 添加请求参数验证中间件
